package com.ruiyou.tb;

import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.PopupMenu;
import android.widget.ProgressBar;
import android.widget.ScrollView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;

import com.tencent.smtt.sdk.WebSettings;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class MainActivity extends Activity
        implements View.OnClickListener, TextView.OnEditorActionListener {

    private X5WebView wvMain;
    private CheckBox cbJS;
    private final String HOME_URL = "http://app.html5.qq.com/navi/index";
    private HashMap<String, String> dataMap;
    private File dataFile;
    private long lastBackPressedTime = 0;

    //储存设置，书签等的相关标志
    static class MapFlag {
        static final String BOOKMARK = "bookmark:";
        static final String SETTING = "setting:";
        static final String INT = "int:";
        static final String STRING = "string:";
        static final String BOOLEAN = "boolean:";
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        setContentView(R.layout.activity_main);

        validatePermission();
        bindView();
        initData();
        if (savedInstanceState == null) {
            wvMain.loadUrl(HOME_URL);
        }
    }

    /**
     * 检查权限
     */
    private void validatePermission() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return;
        String[] ps = {
                Manifest.permission.INTERNET,
                Manifest.permission.WRITE_EXTERNAL_STORAGE
        };
        for (String p : ps) {
            if (checkSelfPermission(p) != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(ps, 3956);
                return;
            }
        }
    }

    /**
     * 初始化相关变量
     */
    private void initData() {
        dataMap = new HashMap<>();
        dataFile = new File(getFilesDir(), "dataFile");
        if (dataFile.exists() && readDataFromFile()) {
            applySettings();//有缓存数据
        }
    }

    /**
     * 绑定控件变量
     */
    private void bindView() {
        wvMain = findViewById(R.id.wv_main);
        EditText etUrl = findViewById(R.id.et_url);
        ProgressBar pb=findViewById(R.id.pb);
        View mainView=findViewById(R.id.ly_main);
        wvMain.setBundleView(this,etUrl,pb,mainView);
        etUrl.setOnEditorActionListener(this);
        int[] mainBtnIds = {
                R.id.btn_add_bookmark,
                R.id.btn_show_toolbar,
                R.id.btn_home,
                R.id.btn_back,
                R.id.btn_forward,
                R.id.btn_refresh,
                R.id.btn_cancel,
                R.id.btn_bookmark,
                R.id.btn_settings,
                R.id.btn_other
        };
        for (int id : mainBtnIds) {
            findViewById(id).setOnClickListener(this);
        }
        cbJS = findViewById(R.id.cb_enable_js);
        cbJS.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                //noinspection deprecation
                wvMain.getSettings().setJavaScriptEnabled(isChecked);
                dataMap.put(MapFlag.SETTING + MapFlag.BOOLEAN + "JavaScriptEnabled", isChecked + "");
            }
        });
    }

    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        writeDataToFile();
        wvMain.saveState(outState);
        super.onSaveInstanceState(outState);
    }

    @Override
    protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
        wvMain.restoreState(savedInstanceState);
        super.onRestoreInstanceState(savedInstanceState);
    }

    /**
     * 从文件读取数据
     */
    private boolean readDataFromFile() {
        try {
            RandomAccessFile raf = new RandomAccessFile(dataFile, "r");
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            byte b;
            while ((b = (byte) raf.read()) != -1) {
                if ((char) b == '\n') {//系统readLine()方法乱码
                    String line = new String(out.toByteArray()).trim();
                    int n = line.indexOf(",");
                    //substring() exclusive the char with the endIndex
                    dataMap.put(line.substring(0, n), line.substring(n + 1));
                    out.reset();//读完一行重置
                } else {
                    out.write(b);
                }
            }
            out.close();
            raf.close();
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 保存数据到文件
     */
    private void writeDataToFile() {
        try {
            if (dataFile.exists()) {
                if (!dataFile.delete()) {
                    showMessage("存储数据异常!");
                }
            }
            RandomAccessFile raf = new RandomAccessFile(dataFile, "rwd");
            for (HashMap.Entry<String, String> entry : dataMap.entrySet()) {
                String line = entry.getKey() + "," + entry.getValue() + "\n";
                raf.write(line.getBytes());
            }
            raf.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 显示消息
     * @param msg         要显示的消息
     *
     */
    private void showMessage(String msg) {
        Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
    }

    /**
     * 编辑动作事件，这里主要处理编辑URL后回车事件
     * @param v        编辑控件
     * @param actionId ...
     * @param event    ...
     * @return 是否已处理，若为否，则系统继续处理
     */
    @Override
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
        if (v.getId() != R.id.et_url) return false;
        String url = v.getText().toString();
        String urlL = url.toLowerCase();
        if (urlL.trim().equals("")) return true;
        if (!urlL.startsWith("http://") && !urlL.startsWith("https://")
                && !urlL.startsWith("file:///")) {
            url = "https://" + url;
        }
        wvMain.loadUrl(url);
        return false;
    }

    /**
     * 显示设置对话框
     */
    private void showSettings() {
        final View dialogView = LayoutInflater.from(this).inflate(R.layout.layout_settings, null, false);
        //设定高度
        DisplayMetrics dms=new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(dms);
        ScrollView sv=dialogView.findViewById(R.id.sv_settings);
        ViewGroup.LayoutParams params =sv.getLayoutParams();
        params.height = dms.heightPixels / 3;
        //添加settings复选框
        final Map<String, Boolean> map = wvMain.getBooleanSettingsMap();
        LinearLayout ly = dialogView.findViewById(R.id.ly_boolean_settings);
        for (String name : map.keySet()) {
            CheckBox cb = new CheckBox(dialogView.getContext());
            cb.setText(name);
            String mn = name.startsWith("Support") ?
                    name.replace("Support", "support") :
                    "get" + name;
            boolean bl = (boolean) wvMain.invokeSettingsMethod(mn, false, null, null);
            cb.setChecked(bl);
            map.put(name, bl);
            cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    map.put(buttonView.getText().toString(), isChecked);
                }
            });
            ly.addView(cb);
        }
        //初始化其他控件
        WebSettings ws = wvMain.getSettings();
        ((EditText) dialogView.findViewById(R.id.et_text_zoom)).setText(String.valueOf(ws.getTextZoom()));
        boolean bl = ws.getUserAgentString().equals(X5WebView.AGENT_STR);
        CheckBox cb = dialogView.findViewById(R.id.cb_user_agent_string);
        cb.setChecked(bl);
        //生产对话框
        final AlertDialog dialog = new AlertDialog.Builder(this).setView(dialogView).create();
        //监听事件
        dialogView.findViewById(R.id.btn_settings_ok).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                for (Map.Entry<String, Boolean> entry : map.entrySet()) {
                    dataMap.put(MapFlag.SETTING + MapFlag.BOOLEAN + entry.getKey(), String.valueOf(entry.getValue()));
                }
                CheckBox cb = dialogView.findViewById(R.id.cb_user_agent_string);
                dataMap.put(MapFlag.SETTING + MapFlag.STRING + "UseAgent", String.valueOf(cb.isChecked()));
                applySettings();
                dialog.dismiss();
            }
        });
        View.OnClickListener ocl = new OnDialogButtonClickListener(dialog, dialogView);
        dialogView.findViewById(R.id.btn_settings_cancel).setOnClickListener(ocl);
        dialogView.findViewById(R.id.btn_settings_clear_cache).setOnClickListener(ocl);
        dialogView.findViewById(R.id.btn_settings_load_default).setOnClickListener(ocl);
        dialog.show();
    }

    /**
     * 显示书签列表
     */
    private void showBookmarks() {
        final View dialogView = LayoutInflater.from(this).inflate(R.layout.layout_bookmark, null, false);
        final AlertDialog dialog = new AlertDialog.Builder(this).setView(dialogView).create();
        final List<HashMap<String, String>> bms = new ArrayList<>();
        for (HashMap.Entry<String, String> entry : dataMap.entrySet()) {
            String url = entry.getKey();
            if (url.startsWith(MapFlag.BOOKMARK)) {
                url = url.substring(MapFlag.BOOKMARK.length());
                HashMap<String, String> hashMap = new HashMap<>();
                hashMap.put("title", entry.getValue());
                hashMap.put("url", url);
                bms.add(hashMap);
            }
        }
        final SimpleAdapter sa = new SimpleAdapter(getApplicationContext(), bms, R.layout.layout_bookmark_item, new String[]{"title", "url"}, new int[]{R.id.tv_bm_item1, R.id.tv_bm_item2});
        final ListView lv = dialogView.findViewById(R.id.lv_bm);
        lv.setAdapter(sa);
        lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                wvMain.loadUrl(bms.get(position).get("url"));
                dialog.dismiss();
            }
        });
        lv.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(final AdapterView<?> parent, final View view, final int position, long id) {
                final PopupMenu menu = new PopupMenu(getApplicationContext(), view);
                menu.getMenu().add("delete");
                menu.getMenu().add("cancel");
                menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
                    @Override
                    public boolean onMenuItemClick(MenuItem item) {
                        if (item.getTitle().equals("delete")) {
                            dataMap.remove(MapFlag.BOOKMARK + bms.get(position).get("url"));
                            bms.remove(position);
                            menu.dismiss();
                            lv.setAdapter(sa);
                        }
                        return true;
                    }
                });
                menu.show();
                return true;
            }
        });
        View.OnClickListener ocl = new OnDialogButtonClickListener(dialog, dialogView);
        dialogView.findViewById(R.id.btn_bm_clear).setOnClickListener(ocl);
        dialogView.findViewById(R.id.btn_bm_ok).setOnClickListener(ocl);
        dialogView.findViewById(R.id.btn_bm_cancel).setOnClickListener(ocl);
        dialog.show();
    }

    /**
     * 自定义对话框按钮点击事件监听器
     */
    private class OnDialogButtonClickListener implements View.OnClickListener {
        View rootView;
        AlertDialog dialog;
        public OnDialogButtonClickListener(AlertDialog dialog, View parent) {
            this.rootView = parent;
            this.dialog = dialog;
        }
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.btn_settings_cancel:
                case R.id.btn_bm_ok:
                case R.id.btn_bm_cancel:
                    dialog.dismiss();
                    break;
                case R.id.btn_settings_clear_cache:
                    wvMain.clearCache(true);
                    showMessage("清理缓存完毕。");
                    break;
                case R.id.btn_settings_load_default:
                    showMessage("nothing to perform");
                    break;
                case R.id.btn_bm_clear:
                    for (Iterator<HashMap.Entry<String, String>> iterator = dataMap.entrySet().iterator(); iterator.hasNext();) {
                        HashMap.Entry<String, String> entry = iterator.next();
                        if (entry.getKey().startsWith(MapFlag.BOOKMARK)) {
                            iterator.remove();
                        }
                    }
                    dialog.dismiss();
                    showBookmarks();
                    break;
            }
        }
    }

    /**
     * 应用settingMap的设置
     */
    private void applySettings() {
        String s;
        for (HashMap.Entry<String, String> entry : dataMap.entrySet()) {
            s = entry.getKey();
            if (s.startsWith(MapFlag.SETTING)) {
                //取出设置
                s = s.substring(MapFlag.SETTING.length());
                if (s.startsWith(MapFlag.BOOLEAN)) {
                    s = "set" + s.substring(8);
                    wvMain.invokeSettingsMethod(s, true, boolean.class, Boolean.parseBoolean(entry.getValue()));
                } else if (s.startsWith(MapFlag.INT)) {
                    s = "set" + s.substring(4);
                    wvMain.invokeSettingsMethod(s, true, int.class, Integer.parseInt(entry.getValue()));
                } else {//string://设置代理
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                        boolean bl = Boolean.parseBoolean(entry.getValue());
                        s = bl ? X5WebView.AGENT_STR : WebSettings.getDefaultUserAgent(this);
                        wvMain.invokeSettingsMethod("setUserAgentString", true, String.class, s);
                    }
                }
            }
        }
        cbJS.setChecked(wvMain.getSettings().getJavaScriptEnabled());
    }

    private void showOtherSetting(View v) {
        final PopupMenu menu = new PopupMenu(this, v);
        menu.getMenu().add("DownloadManager");
        menu.getMenu().add("Test...");
        menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                switch (item.getTitle().toString()) {
                    case "DownloadManager":
                    case "Test...":
                        break;
                }
                return true;
            }
        });
        menu.show();
    }

    /**
     * 主UI按钮点击事件
     * @param v 被点击的按钮
     */
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_add_bookmark:
                //以url为键，因为title可能会有重复
                dataMap.put(MapFlag.BOOKMARK + wvMain.getUrl(), wvMain.getTitle());
                showMessage("添加书签成功。");
                break;
            case R.id.btn_show_toolbar:
                View ly = findViewById(R.id.ly_tool);
                int vi = ly.getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE;
                ly.setVisibility(vi);
                break;
            case R.id.btn_home:
                wvMain.loadUrl(HOME_URL);
                break;
            case R.id.btn_back:
                if (wvMain.canGoBack()) {
                    wvMain.goBack();
                }
                break;
            case R.id.btn_forward:
                if (wvMain.canGoForward()) {
                    wvMain.goForward();
                }
                break;
            case R.id.btn_refresh:
                wvMain.reload();
                break;
            case R.id.btn_cancel:
                wvMain.stopLoading();
                break;
            case R.id.btn_bookmark:
                showBookmarks();
                break;
            case R.id.btn_settings:
                showSettings();
                break;
            case R.id.btn_other:
                showOtherSetting(v);
                break;
        }
    }

    /**
     * 设备返回键事件处理
     */
    @Override
    public void onBackPressed() {
        long currentTime = System.currentTimeMillis();
        if (wvMain.canGoBack()) {
            wvMain.goBack();
            return;
        }
        if (currentTime - lastBackPressedTime > 3000) {
            lastBackPressedTime = currentTime;
            showMessage("3秒内再按一次退出程序！");
            return;
        }
        super.onBackPressed();
    }
}
